// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"
#include "Valeur.h"

/*
 * LecteurFonction.h inclue Arbre.h
 * => Arbre.h ne peut pas inclure LecteurFonction.h /!\
 * => On fait une déclaration anticipée de la classe LecteurFonction
 * => On inclue LecteurFonction.h dans Arbre.cpp
 */
class LecteurFonction;

////////////////////////////////////////////////////////////////////////////////

/*! \file Arbre.h
        \brief La spécification des classes formant l'arbre
        Décrit la liste des méthodes et attributs associés à l'arbre du lecteur
        \author Ribes Gaël, Pauli Marie
        \date 04.01.2012
 */

/*! \class Noeud
        \brief La classe représentant les Noeuds.
Cette classe permet de représenter sous la forme d'un objet
une variable de type Noeud. Les méthodes suivantes sont associées
à un objet de type Noeud :
        \li getValeur
        \li afficher
 */


class Noeud {
    // classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
    // Remarque : la classe ne contient aucun constructeur
public:


    /*! \fn Valeur* getValeur()
    \brief Retourne la valeur du noeud. Methode non implémentée (rend la classe abstraite).
    \return La "valeur" du Noeud.
     */
    virtual Valeur* getValeur() = 0; // méthode pure (non implémentée) qui rend la classe abstraite

    /*! \fn void afficher(unsigned short indentation = 0)
    \brief affiche le Noeud
    \param indentation - marge avant l'affichage
     */
    virtual void afficher(unsigned short indentation = 0) {
        cout << setw(4 * indentation) << " ";
    }
    // pour afficher un noeud avec un décalage (indentation) proportionnel à son niveau dans l'arbre

    /*! \fn virtual ~Noeud()
    \brief Destructeur de la classe Noeud
     */
    virtual ~Noeud() {
    } // présence d'un destructeur virtuel conseillée dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////

class NoeudSeqInst : public Noeud {
    // classe pour représenter un noeud "sequence d'instruction"
    // qui a autant de fils que d'instructions dans la séquence
public:
    NoeudSeqInst(); // construit une séquence d'instruction vide

    ~NoeudSeqInst() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation = 0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction); // ajoute une instruction à la séquence

private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////

class NoeudAffectation : public Noeud {
    // classe pour représenter un noeud "affectation"
    // composé de 2 fils : la variable et l'expression qu'on lui affecte
public:
    NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation

    ~NoeudAffectation() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation = 0); // affiche l'affectation

private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudOperateurBinaire : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
    // construit une opération binaire : operandeGauche operateur OperandeDroit

    ~NoeudOperateurBinaire() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation = 0); // affiche l'opération

private:
    Symbole operateur;
    Noeud* operandeGauche;
    Noeud* operandeDroit;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstCommutation : public Noeud {
    // classe pour représenter un noeud de commutation
    // composé de séquences d'instructions
public:
    NoeudInstCommutation(); // Construit une commutation
    ~NoeudInstCommutation() {};
    
    virtual Valeur* getValeur() = 0;
    virtual void afficher(unsigned short indentation = 0) {
        cout << setw(4 * indentation) << " ";
    }
    void ajouterCas(Noeud* cond, Noeud* seqInst);
    
protected:
    vector<Noeud*> conds;
    vector<Noeud*> seqInsts;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstSi : public NoeudInstCommutation {
    // classe pour représenter un noeud "si"
    // composé de conditions et sequences d'instructions
public:
    NoeudInstSi(Noeud* condSi, Noeud* seqInstSi); // construit un si

    ~NoeudInstSi() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue les conditions et la séquence d'instruction à évaluer
    void afficher(unsigned short indentation = 0); // affiche le si
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstChoix : public NoeudInstCommutation {
    // classe pour représenter un noeud "choix"
    // composé de cas et sequences d'instructions
public:
    NoeudInstChoix(); // construit un choix

    ~NoeudInstChoix() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue les conditions et la séquence d'instruction à évaluer
    void afficher(unsigned short indentation = 0); // affiche le choix
};

////////////////////////////////////////////////////////////////////////////////

class NoeudBoucle : public Noeud {
    // classe pour représenter un noeud boucle (tantque,repeter,pour)
    // composé d'une condition et d'une séquence d'instructions
public:
    NoeudBoucle(Noeud* cond, Noeud* seqInst); // construit une boucle

    ~NoeudBoucle() {
    } // à cause du destructeur virtuel de la classe Noeud
    virtual Valeur* getValeur() = 0;

    virtual void afficher(unsigned short indentation = 0) {
        cout << setw(4 * indentation) << " ";
    }

protected:

    inline Noeud* getCond() {
        return this->cond;
    };

    inline Noeud* getSeqInst() {
        return this->seqInst;
    };

private:
    Noeud* cond;
    Noeud* seqInst;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstTq : public NoeudBoucle {
    // classe pour représenter un noeud tantque
    // composé d'une condition et d'une séquence d'instructions
public:
    NoeudInstTq(Noeud* cond, Noeud* seqInst); // construit une boucle tantque

    ~NoeudInstTq() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur();
    void afficher(unsigned short indentation = 0);

};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstRepeter : public NoeudBoucle {
    // classe pour représenter un noeud repeter
    // composé d'une séquence d'instructions et d'une condition
public:
    NoeudInstRepeter(Noeud* cond, Noeud* seqInst); // construit une boucle repeter

    ~NoeudInstRepeter() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur();
    void afficher(unsigned short indentation = 0);

};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstPour : public NoeudBoucle {
    // classe pour représenter un noeud pour
    // composé d'une séquence d'instructions, d'une condition et de 2 affectations
public:
    NoeudInstPour(Noeud* aff1, Noeud* cond, Noeud* aff2, Noeud* seqInst); // construit une boucle pour
    // pour (aff1;cond;aff2) seqInst;

    ~NoeudInstPour() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur();
    void afficher(unsigned short indentation = 0);
private:
    Noeud* aff1;
    Noeud* aff2;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstLire : public Noeud {
    // classe pour représenter un noeud lire
    // composé d'une variable
public:
    NoeudInstLire(Noeud* variable); // construit un lire

    ~NoeudInstLire() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur();
    void afficher(unsigned short indentation = 0);

private:
    Noeud* variable;

};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstEcrire : public Noeud {
    // classe pour représenter un noeud ecrire
    // composé d'un argument (chaine ou expression)
public:
    NoeudInstEcrire(Noeud* argument); // construit un ecrire

    ~NoeudInstEcrire() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur();
    void afficher(unsigned short indentation = 0);

private:
    Noeud* argument;

};

////////////////////////////////////////////////////////////////////////////////

class NoeudAppelFonction : public Noeud {
    // classe pour représenter un noeud appel de fonction
    // composé du nom de la fonction et des paramètres
public:
    NoeudAppelFonction(string nom, vector<Noeud*> parametres, vector<LecteurFonction*> * tf); // construit un appel de fonction

    ~NoeudAppelFonction() {
    } // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur();
    void afficher(unsigned short indentation = 0);

private:
    string nom;
    vector<LecteurFonction*>* tf;
    vector<Noeud*> parametres;
};








#endif /* ARBRE_H_ */
